package gfx;

import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import java.nio.FloatBuffer;
import java.util.HashMap;
import java.util.Map;

import javax.microedition.khronos.opengles.GL10;

import util.GameVars;
import util.Logger;

import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.PointF;

public class Glyphs {
	Context context;
	
	// GL Crap
	// Texture stuff
	private static FloatBuffer textureBuffer;
	private static float texture[] = {
			0.0f, 1.0f,
			0.0f, 0.0f,
			1.0f, 1.0f,
			1.0f, 0.0f
	};
	
	private static FloatBuffer vertexBuffer;
	private static float vertices[];

	// Map to associate a bitmap to each character
	static HashMap<Character, Bitmap> glyphMap = new HashMap<Character, Bitmap>(62);

	static int glyphWidth;	// width in pixels of one character
	static int glyphHeight;	// height in pixels of one character

	// the characters in the English alphabet
//	public char[] charactersL = new char[] { 'a', 'b', 'c', 'd', 'e', 'f', 'g',
//			'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't',
//			'u', 'v', 'w', 'x', 'y', 'z' };
	public char[] charactersU = new char[] { 'A', 'B', 'C', 'D', 'E', 'F', 'G',
			'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T',
			'U', 'V', 'W', 'X', 'Y', 'Z' , ' ', '/', '+', '='};
	public char[] numbers = new char[] { '0', '1', '2', '3', '4', '5', '6', '7',
			'8', '9' };
	public char[] punctuation = new char[] {'.', ',', '!', '?', '`', '\'', '-', ':', 
			'(', ')'};

	static int temp;
	static int k;
	private static short indent;
	
	private static float mod = .2f;
	
	private static int index;
	
	private static char[] stringArray;
	
	private boolean isLoaded;
	
	private static PointF location;

	public Glyphs(){
	}

	private static class GlyphHolder {
		public static final Glyphs instance = new Glyphs();
	}

	public static Glyphs getInstance(){
		return GlyphHolder.instance;
	}
	
	public void init(){
		isLoaded = false;
		glyphWidth = 8;
		glyphHeight = 16;
		vertices = new float[12];
		
		// New Implementation Test
		vertices[0] = vertices[3] = - (float) 16 / (float)32 * mod;
		vertices[1] = vertices[7] = -mod;
		vertices[2] = vertices[5] = vertices[8] = vertices[11] = 0;
		vertices[4] = vertices[10] = mod;
		vertices[6] = vertices[9] = (float) 16 / (float)32 * mod;
		
		location = new PointF();
		
		isLoaded = true;
	}

	public void setLoadedState(boolean state){ isLoaded = state; }
	public boolean isLoaded(){ return isLoaded; }
	
	public static void drawMultiLinedString(GL10 gl, String mText, PointF loc, short alignment, float glWidth){
		if(loc == null)
			location.set(0, 0);
		else location.set(loc);
		if(mText.length() * (mod) > glWidth){
			index = (int)(glWidth / (mod)) - 1;
			while(true){
				stringArray = mText.toCharArray();
				while(stringArray[index] != ' ')
					--index;
				drawString(gl, mText.substring(0, index), location, alignment);
				mText = mText.substring(index, mText.length());
				gl.glTranslatef(0, location.y - (2 * mod), 0);
				if((int)(glWidth / (mod)) > mText.length())
					break;
				else index = (int)(glWidth / (mod)) - 1;
			}
		}
		drawString(gl, mText, location, alignment);
	}
	
	// Current.  Avoiding Canvas here.  Appears to have fixed everything.
	// And everything appears to be working as intended.
	public static void drawString(GL10 gl, String mText, PointF loc, short alignment){	
		
		ByteBuffer byteBuffer = ByteBuffer.allocateDirect(vertices.length*4);
		byteBuffer.order(ByteOrder.nativeOrder());
		
		// allocates the memory from the byte buffer
		vertexBuffer = byteBuffer.asFloatBuffer();
		
		// fill the vertexBuffer with the vertices
		vertexBuffer.put(vertices);
		
		// set the cursor position to the beginning of the buffer
		vertexBuffer.position(0);
		
		byteBuffer = ByteBuffer.allocateDirect(texture.length*4);
		byteBuffer.order(ByteOrder.nativeOrder());
		textureBuffer = byteBuffer.asFloatBuffer();
		textureBuffer.put(texture);
		textureBuffer.position(0);
		// End MOVED
		
		// Test
		gl.glPushMatrix();

		// Create Filtered Texture
		//																	NEAREST = Crisp  LINEAR = Blurred
		gl.glTexParameterf(GL10.GL_TEXTURE_2D, GL10.GL_TEXTURE_MIN_FILTER, GL10.GL_NEAREST);
		gl.glTexParameterf(GL10.GL_TEXTURE_2D, GL10.GL_TEXTURE_MAG_FILTER, GL10.GL_NEAREST);
		
		// Point to Buffers
		gl.glEnableClientState(GL10.GL_VERTEX_ARRAY);
		gl.glEnableClientState(GL10.GL_TEXTURE_COORD_ARRAY);
		
		// Set Face
		gl.glFrontFace(GL10.GL_CW);
		
		// Point to buffer
		gl.glVertexPointer(3, GL10.GL_FLOAT, 0, vertexBuffer);
		gl.glTexCoordPointer(2, GL10.GL_FLOAT, 0, textureBuffer);
		
		if(loc != null)
			gl.glTranslatef(loc.x, loc.y, 0);

		for (k = 0; k < mText.length(); ++k) {
			Character ch = Character.toUpperCase(mText.charAt(k));
			if (glyphMap.get(ch) != null) {
				gl.glPushMatrix();
				switch(alignment){
				// Left Justified
				case GameVars.TEXT_ALIGNMENT_LEFT:
					gl.glTranslatef(((mText.length() * 0.5f) * mod) + (k - mText.length() * 0.5f) * mod, 0, 0);
					break;
				// Center
				case GameVars.TEXT_ALIGNMENT_CENTER:
					gl.glTranslatef((k - mText.length() * 0.5f) * mod, 0, 0);
					break;
				// Right Justified
				case GameVars.TEXT_ALIGNMENT_RIGHT:
					gl.glTranslatef((k - mText.length() * 0.5f) * mod - (mText.length() * 0.5f) * mod, 0, 0);
					break;
				}
				gl.glBindTexture(GL10.GL_TEXTURE_2D, Spritesheet.getInstance().glyphTextureMap.get(ch)[0]);
				gl.glDrawArrays(GL10.GL_TRIANGLE_STRIP, 0, vertices.length / 3);
				gl.glPopMatrix();
			}
		}
		
		gl.glColor4f(1, 1, 1, 1);
		
		// Disable Client State before Leaving
		gl.glDisableClientState(GL10.GL_VERTEX_ARRAY);
		gl.glDisableClientState(GL10.GL_TEXTURE_COORD_ARRAY);
		
		gl.glPopMatrix();
	}

	@Deprecated
	public static void drawDialog(GL10 gl, String mText){
//		if(!isLoaded){			
			// a float has 4 bytes so we allocate for each coordinate 4 bytes
			ByteBuffer byteBuffer = ByteBuffer.allocateDirect(vertices.length*4);
			byteBuffer.order(ByteOrder.nativeOrder());
			
			// allocates the memory from the byte buffer
			vertexBuffer = byteBuffer.asFloatBuffer();
			
			// fill the vertexBuffer with the vertices
			vertexBuffer.put(vertices);
			
			// set the cursor position to the beginning of the buffer
			vertexBuffer.position(0);
			
			byteBuffer = ByteBuffer.allocateDirect(texture.length*4);
			byteBuffer.order(ByteOrder.nativeOrder());
			textureBuffer = byteBuffer.asFloatBuffer();
			textureBuffer.put(texture);
			textureBuffer.position(0);
			// End MOVED
		
		// Test
		gl.glPushMatrix();
		
		// Point to Buffers
		gl.glEnableClientState(GL10.GL_VERTEX_ARRAY);
		gl.glEnableClientState(GL10.GL_TEXTURE_COORD_ARRAY);
		
		// Set Face
		gl.glFrontFace(GL10.GL_CW);
		
		// Point to buffer
		gl.glVertexPointer(3, GL10.GL_FLOAT, 0, vertexBuffer);
		gl.glTexCoordPointer(2, GL10.GL_FLOAT, 0, textureBuffer);
		
		gl.glTranslatef(indent * mod, 0, 0);
		
		for (k = 0; k < mText.length(); ++k) {
			Character ch = mText.charAt(k);
			if (glyphMap.get(ch) != null) {
				gl.glPushMatrix();
				gl.glTranslatef(k * mod, 0, 0);
				gl.glBindTexture(GL10.GL_TEXTURE_2D, Spritesheet.getInstance().glyphTextureMap.get(ch)[0]);
				gl.glDrawArrays(GL10.GL_TRIANGLE_STRIP, 0, vertices.length / 3);
				gl.glPopMatrix();
			}
		}
		
		// Disable Client State before Leaving
		gl.glDisableClientState(GL10.GL_VERTEX_ARRAY);
		gl.glDisableClientState(GL10.GL_TEXTURE_COORD_ARRAY);
		
		gl.glPopMatrix();
	}
}